Add test coverage for publications#614
Conversation
Open the dropdown on focus (not just mouse click), expose aria-expanded / aria-controls / aria-activedescendant on the input, label the panel as a group, restore focus to the input on Escape, and let users navigate the list with ↑/↓/Home/End and apply with Enter. Active item scrolls into view, and a muted helper hint describes the shortcuts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR increases test coverage around the publications feature area, and also introduces two user-facing improvements: keyboard navigation for the saved-searches dropdown and multi-select architecture selection in the “Add publication” form.
Changes:
- Add/expand publications-related component tests (header search param update, filtering behavior, empty state navigation, details side panel).
- Improve saved-searches dropdown keyboard accessibility (arrow-key navigation, ARIA wiring, focus/blur behavior) and add extensive tests.
- Update publication creation to support selecting multiple architectures (form + validation + tests), with changesets for both user-facing updates.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/tests/setup.ts | Adds a scrollIntoView no-op polyfill for jsdom-based tests. |
| src/features/saved-searches/components/SearchBoxWithSavedSearches/SearchBoxWithSavedSearches.tsx | Adds focus management, keyboard navigation, and ARIA attributes for the saved-searches dropdown. |
| src/features/saved-searches/components/SearchBoxWithSavedSearches/SearchBoxWithSavedSearches.test.tsx | Adds keyboard accessibility test coverage for the saved-searches dropdown behavior. |
| src/features/saved-searches/components/SearchBoxWithSavedSearches/SearchBoxWithSavedSearches.module.scss | Styles keyboard shortcut hint and <kbd> presentation. |
| src/features/saved-searches/components/SavedSearchList/SavedSearchList.tsx | Adds active-item highlighting and scroll-into-view behavior for aria-activedescendant navigation. |
| src/features/saved-searches/components/SavedSearchList/SavedSearchList.module.scss | Adds styling for the active (highlighted) item. |
| src/features/publications/components/PublicationsHeader/PublicationsHeader.test.tsx | Tests that submitting search updates the URL query param. |
| src/features/publications/components/PublicationsContainer/PublicationsContainer.test.tsx | Adds filtering tests for different query syntaxes (prefix vs plain text). |
| src/features/publications/components/PublicationDetailsSidePanel/PublicationDetailsSidePanel.test.tsx | Adds loading and loaded-state coverage for the details side panel. |
| src/features/publications/components/NoPublicationsTargetEmptyState/NoPublicationTargetEmptyState.test.tsx | Tests CTA navigation to the “add publication target” route. |
| src/features/publications/components/AddPublicationForm/types.ts | Changes uploader_architectures to a string[]. |
| src/features/publications/components/AddPublicationForm/helpers.ts | Updates Yup validation and payload generation for architecture arrays. |
| src/features/publications/components/AddPublicationForm/constants.ts | Updates initial values for architecture arrays. |
| src/features/publications/components/AddPublicationForm/AddPublicationForm.tsx | Replaces single-select architectures with MultiSelectField and updates form state handling. |
| src/features/publications/components/AddPublicationForm/AddPublicationForm.test.tsx | Updates tests for MultiSelect architectures + adds validation/submission coverage. |
| src/features/mirrors/components/MirrorDetails/MirrorDetails.test.tsx | Expands assertions, but currently includes a duplicated test case. |
| .changeset/twelve-suns-sing.md | Changeset for saved-searches keyboard navigation enhancement. |
| .changeset/light-corners-lick.md | Changeset for multi-architecture selection in publication creation. |
Comments suppressed due to low confidence (1)
src/features/mirrors/components/MirrorDetails/MirrorDetails.test.tsx:51
- This file contains two identical test cases named "displays preserve signatures status" with the same assertions. Keeping both adds redundant runtime and makes future failures harder to interpret; consider removing one or changing the second to cover the opposite value (e.g. preserveSignatures=false => "No").
it("displays preserve signatures status", async () => {
const mirrorWithPreserveSignatures = mirrors.find(
({ preserveSignatures }) => preserveSignatures,
);
| --- | ||
| "landscape-ui": patch | ||
| --- | ||
|
|
||
| Keyboard a11y and arrow-key navigation for saved-searches dropdown |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Comments suppressed due to low confidence (1)
src/features/mirrors/components/MirrorDetails/MirrorDetails.test.tsx:45
- This test renders
mirrorWithPreserveSignatures(the first mock with preserveSignatures=true), but then asserts the heading formirrors[0].displayName. With the current mocks,mirrorWithPreserveSignaturesismirrors[1], so this assertion will fail. Assert againstmirrorWithPreserveSignatures.displayNameinstead.
it("displays preserve signatures status", async () => {
const mirrorWithPreserveSignatures = mirrors.find(
({ preserveSignatures }) => preserveSignatures,
);
assert(mirrorWithPreserveSignatures);
renderWithProviders(
<Suspense fallback={<LoadingState />}>
<MirrorDetails />
</Suspense>,
undefined,
`?name=${mirrorWithPreserveSignatures.name}`,
);
await expectLoadingState();
expect(
screen.getByRole("heading", { name: mirrors[0].displayName }),
).toBeInTheDocument();
| --- | ||
| "landscape-ui": patch | ||
| --- | ||
|
|
||
| Allow selection of more than one architecture when creating a publication |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
| it("handles batchGet response with no mirrors array and nameless mirrors", async () => { | ||
| server.use( | ||
| http.post(`${API_URL_DEB_ARCHIVE}mirrors:batchGet`, () => | ||
| HttpResponse.json({ mirrors: [{ displayName: "no-name-mirror" }] }), | ||
| ), |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
@gesquivelgaghi good call. Added tests to bring /mirrors coverage up to 92% |
| describe("MirrorActions", () => { | ||
| it("renders", () => { | ||
| renderWithProviders( | ||
| const [mirror, , mirrorWithNoPublications] = [...mirrors] as [ |
There was a problem hiding this comment.
can we use .find to get a mirror with no publications instead just so if the mocks are changed later these tests aren't as fragile. Also [...mirrors] as [...] doesn't seem necessary
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 8 comments.
Comments suppressed due to low confidence (5)
src/features/mirrors/components/AddMirrorForm/AddMirrorForm.test.tsx:90
- This no longer verifies the snapshot-specific payload. Because the MSW create handler accepts any body and always succeeds, the test would pass even if the form stopped appending the selected snapshot date to
archiveRoot.
await user.click(screen.getByRole("button", { name: "Add mirror" }));
expect(
await screen.findByText("You have successfully added Name."),
).toBeInTheDocument();
src/features/mirrors/components/AddMirrorForm/AddMirrorForm.test.tsx:169
- This test fills several third-party mirror fields but only asserts the generic success notification. Since the create handler does not validate the body, regressions in
archiveRoot,distribution,components,architectures, orgpgKeyserialization would not fail the test anymore.
await user.click(screen.getByRole("button", { name: "Add mirror" }));
expect(
await screen.findByText("You have successfully added Name."),
).toBeInTheDocument();
src/features/mirrors/components/EditMirrorForm/EditMirrorForm.test.tsx:195
- This test toggles the download options but only verifies the success notification. Because the update handler does not validate the request body, the test would still pass if
downloadUdebs,downloadSources, ordownloadInstallerstopped being sent correctly.
expect(
await screen.findByText(
`You have successfully edited ${mirror.displayName}.`,
),
).toBeInTheDocument();
src/features/mirrors/components/AddMirrorForm/AddMirrorForm.test.tsx:115
- The preserve-signatures behavior is no longer asserted after submission. The current success-notification check would still pass if
preserveSignatureswere omitted or sent asfalse, because the MSW handler does not validate the request body.
await user.click(screen.getByRole("button", { name: "Add mirror" }));
expect(
await screen.findByText("You have successfully added Name."),
).toBeInTheDocument();
src/features/mirrors/components/EditMirrorForm/EditMirrorForm.test.tsx:118
- The previous payload assertion ensured that keeping the current key did not send a
gpgKeyupdate. Replacing it with a success-notification check leaves that behavior uncovered, because the MSW handler will succeed even if the form accidentally clears or replaces the key.
await user.click(screen.getByRole("button", { name: "Save changes" }));
expect(
await screen.findByText(
`You have successfully edited ${mirror.displayName}.`,
| @@ -58,6 +61,84 @@ describe("PublicationsContainer", () => { | |||
| expect( | |||
| screen.queryByRole("button", { name: "Add publication" }), | |||
| ).not.toBeInTheDocument(); | |||
TICS Quality Gate❌ Failedlandscape-ui
❌ Condition “No new Coding Standard Violations for level 1, 2, 3 with respect to Previous analysis” failed 1 time.
|
||||||||
| File | Issues | |
|---|---|---|
| 🪲 Total | ❌ Blocking | |
|
src/features/publications/components/AddPublicationForm/AddPublicationForm.tsx | 196 | +196 |
See the results in the TICS Viewer
The following files have been checked for this project
- src/features/publications/components/AddPublicationForm/AddPublicationForm.tsx

Summary
DELETE/PATCHhandlers mutated shared mock array across tests; fix copies array locally and resets inafterEach.PublicationsContainertest corrected to wait for settled empty state and assert button count instead of absence, fixing race with two sequential loading spinners.Release Impact
Pick the target branch (see RELEASES.md for the full model):
dev— internal testing → publishes toppa-build-devmain— next beta → publishes toppa-buildrelease/YY.MM— point release on a maintained cycle → publishes toppa-build-YY.MM(and toppa-build-stableif this is the currently-promoted branch). Specify cycle:release/____Change type (tick one):
Checklist
pnpm changeset(orpnpm changeset --emptyif no CHANGELOG line is warranted) and committed the resulting.mdfile. Required for PRs targetingmainandrelease/*; enforced by theChangeset checkworkflow.scripts/).Versioning Reminder
Important
Landscape UI uses CalVer (
YY.MM.Point.Build). Version derivation by branch:main/point/*→YY.MM.0.<run>-betadev→YY.MM.0.<run>-devrelease/YY.MM→YY.MM.1.<run>(cycle pinned by branch name)